package com.spsoft.vatoutinv.service.vmsfullyfmmessage.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.spsoft.core.enums.ResponseEnum;
import com.spsoft.core.exception.BaseException;
import com.spsoft.core.model.Result;
import com.spsoft.core.model.bo.TokenUser;
import com.spsoft.core.model.leqidmz.param.AssignedCodeParams;
import com.spsoft.core.model.leqidmz.response.AssignedCodeResponseVO;
import com.spsoft.core.utils.BeanUtils;
import com.spsoft.core.utils.StringUtil;
import com.spsoft.einvoicetodmz.service.DmzApiClientService;
import com.spsoft.vatoutinv.constants.CommonConstant;
import com.spsoft.vatoutinv.entity.vmsfullyfmmessage.VmsFullYfmDetails;
import com.spsoft.vatoutinv.entity.vmsfullyfmmessage.VmsFullYfmMessage;
import com.spsoft.vatoutinv.entity.vmsfullyfmmessage.VmsFullYfmMessageLog;
import com.spsoft.vatoutinv.mapper.VmsFullYfmMessageLogMapper;
import com.spsoft.vatoutinv.mapper.VmsFullYfmMessageMapper;
import com.spsoft.vatoutinv.model.dto.vmsfullyfmmessage.VmsFullYfmMessageDto;
import com.spsoft.vatoutinv.model.vo.vmsfullyfmmessage.VmsFullYfmMessageVo;
import com.spsoft.vatoutinv.service.vmsfullyfmmessage.VmsFullYfmDetailsService;
import com.spsoft.vatoutinv.service.vmsfullyfmmessage.VmsFullYfmMessageService;
import com.spsoft.vms.redis.RedisService;
import com.spsoft.vms.redis.constant.RedisConstant;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 预赋码信息管理表 服务实现类
 * </p>
 *
 * @author chenxudong
 * @since 2023-11-28
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class VmsFullYfmMessageServiceImpl extends ServiceImpl<VmsFullYfmMessageMapper, VmsFullYfmMessage> implements VmsFullYfmMessageService {

    public static final String LOG_MSG = "(预赋码信息控制层)";

    private final VmsFullYfmMessageLogMapper vmsFullYfmMessageLogMapper;

    private final VmsFullYfmDetailsService vmsFullYfmDetailsService;

    private final RedisService redisService;

    private final DmzApiClientService dmzApiClientService;

    @Override
    public Result<IPage<VmsFullYfmMessageVo>> queryVmsFullYfmMessage(VmsFullYfmMessageDto vmsFullYfmMessageDto) {
        // 查询数据库获取预赋码信息
        Page<VmsFullYfmMessage> page = new Page<>(vmsFullYfmMessageDto.getPageNo(), vmsFullYfmMessageDto.getPageSize());
        LambdaQueryWrapper<VmsFullYfmMessage> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(VmsFullYfmMessage::getDeptCode, vmsFullYfmMessageDto.getDeptCode());
        queryWrapper.orderByDesc(VmsFullYfmMessage::getCreateTime);
        Page<VmsFullYfmMessage> IPage = this.page(page, queryWrapper);

        // 将数据库返回数据转换为VO返回前端
        IPage<VmsFullYfmMessageVo> IPageVo = IPage.convert(item -> {
            VmsFullYfmMessageVo vo = new VmsFullYfmMessageVo();
            // 转换数据
            BeanUtils.copyBeanProp(vo, item);
            return vo;
        });
        return Result.OK(IPageVo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Object> getVmsFullYfmMessageByLq(VmsFullYfmMessageDto vmsFullYfmMessageDto, TokenUser userInfo) {
        String redisLockKey = String.format(RedisConstant.REDIS_SYED_YFM_LOCK_KEY, userInfo.getDeptCode());
        RLock lock = redisService.getLock(redisLockKey);
        boolean success = redisService.tryLock(lock, 3, 500);
        if (!success) {
            log.info("{}尝试指定次数后均未获取到锁，返回系统繁忙", LOG_MSG);
            return Result.ERROR(ResponseEnum.REDIS_LOCK_NO_GET);
        }
        log.info("{}redisson上锁成功，key：{}", LOG_MSG, redisLockKey);
        try {
            // 调用乐企接口获取预赋码信息
            AssignedCodeParams params = new AssignedCodeParams();
            params.setLysl(Math.toIntExact(vmsFullYfmMessageDto.getLysl()));
            params.setYwlsh(vmsFullYfmMessageDto.getYwlsh());
            params.setNsrsbh(vmsFullYfmMessageDto.getNsrsbh());
            params.setCreateUser(userInfo.getUserCode());
            params.setDeptCode(userInfo.getDeptCode());
            Result<AssignedCodeResponseVO> result = dmzApiClientService.assignedCode(params, null);
            log.info("{}乐企返回预赋码信息：{}", LOG_MSG, JSONObject.toJSONString(result));

            // 先记录日志操作(LOG_BASE)和乐企返回的当次可用税率记录(LOG)
            VmsFullYfmMessageLog vmsFullYfmMessageLog = new VmsFullYfmMessageLog();
            vmsFullYfmMessageLog.setDeptCode(userInfo.getDeptCode());
            vmsFullYfmMessageLog.setNsrsbh(vmsFullYfmMessageDto.getNsrsbh());
            vmsFullYfmMessageLog.setCreateTime(new Date());
            vmsFullYfmMessageLog.setCreateUser(userInfo.getUserCode());
            vmsFullYfmMessageLog.setCreateUsername(userInfo.getUserName());
            vmsFullYfmMessageLog.setYwlsh(params.getYwlsh());

            if (ResponseEnum.SUCCESS.getCode().equals(result.getCode())) {
                AssignedCodeResponseVO data = result.getData();

                vmsFullYfmMessageLog.setOperateStatus(CommonConstant.STR_01);
                vmsFullYfmMessageLog.setOperateMsg(JSONObject.toJSONString(data));
                // 记录日志操作(LOG表)
                vmsFullYfmMessageLogMapper.insert(vmsFullYfmMessageLog);

                // 字段补全
                VmsFullYfmMessage vmsFullYfmMessage = new VmsFullYfmMessage();
                vmsFullYfmMessage.setLogId(vmsFullYfmMessageLog.getId());
                vmsFullYfmMessage.setDeptCode(userInfo.getDeptCode());
                vmsFullYfmMessage.setNsrsbh(vmsFullYfmMessageDto.getNsrsbh());
                vmsFullYfmMessage.setFpqshm(data.getFpqshm());
                vmsFullYfmMessage.setFpzzhm(data.getFpzzhm());
                vmsFullYfmMessage.setLysl(Long.valueOf(data.getLysl()));
                vmsFullYfmMessage.setCreateTime(new Date());
                vmsFullYfmMessage.setCreateUser(userInfo.getUserCode());
                vmsFullYfmMessage.setCreateUsername(userInfo.getUserName());
                vmsFullYfmMessage.setUpdateTime(new Date());
                vmsFullYfmMessage.setUpdateUser(userInfo.getUserCode());
                vmsFullYfmMessage.setUpdateUsername(userInfo.getUserName());
                // 当前待使用发票号码 默认为 发票起始号码
                vmsFullYfmMessage.setDqdsyfphm(vmsFullYfmMessage.getFpqshm());
                // 号段剩余总数 默认为 领用数量
                vmsFullYfmMessage.setHdsyzs(vmsFullYfmMessage.getLysl());
                // 号段获取日期 默认为 创建时间
                vmsFullYfmMessage.setSucessedTime(vmsFullYfmMessage.getCreateTime());
                // 插入预赋码信息表
                this.baseMapper.insert(vmsFullYfmMessage);

                List<VmsFullYfmDetails> vmsFullYfmDetailList = new ArrayList<>();
                BigInteger fpqshm = new BigInteger(vmsFullYfmMessage.getFpqshm());
                BigInteger fpzzhm = new BigInteger(vmsFullYfmMessage.getFpzzhm());
                while (fpqshm.compareTo(fpzzhm) <= 0) {
                    VmsFullYfmDetails vmsFullYfmDetail = new VmsFullYfmDetails();
                    vmsFullYfmDetail.setYfmid(vmsFullYfmMessage.getYfmid());
                    vmsFullYfmDetail.setFphm(StringUtil.toString(fpqshm));
                    vmsFullYfmDetail.setUseStatus(CommonConstant.STR_0);
                    vmsFullYfmDetail.setDeptCode(userInfo.getDeptCode());
                    vmsFullYfmDetail.setDelFlag(CommonConstant.STR_0);
                    vmsFullYfmDetail.setCreateTime(new Date());
                    vmsFullYfmDetail.setCreateUser(userInfo.getUserCode());
                    vmsFullYfmDetail.setUpdateTime(new Date());
                    vmsFullYfmDetail.setUpdateUser(userInfo.getUserCode());

                    vmsFullYfmDetailList.add(vmsFullYfmDetail);
                    fpqshm = fpqshm.add(new BigInteger(CommonConstant.STR_1));
                }
                // 插入预赋码信息明细表
                vmsFullYfmDetailsService.saveBatch(vmsFullYfmDetailList);
            } else {
                vmsFullYfmMessageLog.setOperateStatus(CommonConstant.STR_02);
                vmsFullYfmMessageLog.setOperateMsg(result.getMessage());
                vmsFullYfmMessageLogMapper.insert(vmsFullYfmMessageLog);
                return Result.ERROR(result.getCode(), result.getMessage());
            }
        } catch (Exception e) {
            log.error("{}出现异常:{}", LOG_MSG, e);
            throw new BaseException(e.getMessage());
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                log.info("redisson释放锁成功，key为:{}", redisLockKey);
                lock.unlock();
            } else {
                log.info("redisson释放锁失败，key为:{}", redisLockKey);
            }
        }
        return Result.OK_MSG(ResponseEnum.LEQI_SUCCESS.getMsg());
    }

    @Override
    public List<VmsFullYfmMessage> getYfmByDeptCode(String deptCode) {
        LambdaQueryWrapper<VmsFullYfmMessage> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(VmsFullYfmMessage::getDeptCode, deptCode);
        queryWrapper.gt(VmsFullYfmMessage::getHdsyzs, Long.parseLong(CommonConstant.STR_0));
        // 预赋码禁止跨年度使用，获取当前年份
        String year = StringUtil.toString(DateUtil.thisYear()).substring(2);
        queryWrapper.gt(VmsFullYfmMessage::getFpqshm, year + "000000000000000000");
        queryWrapper.orderByAsc(VmsFullYfmMessage::getCreateTime);
        return list(queryWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Object> updateYfmByDetail(VmsFullYfmMessage vmsFullYfmMessage, TokenUser tokenUser) {
        LambdaQueryWrapper<VmsFullYfmDetails> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(VmsFullYfmDetails::getYfmid, vmsFullYfmMessage.getYfmid());
        queryWrapper.eq(VmsFullYfmDetails::getUseStatus, CommonConstant.STR_0);
        queryWrapper.eq(VmsFullYfmDetails::getDelFlag, CommonConstant.STR_0);
        queryWrapper.orderByAsc(VmsFullYfmDetails::getFphm);
        int count = vmsFullYfmDetailsService.count(queryWrapper);

        if (count == 0) {
            vmsFullYfmMessage.setHdsyzs(0L);
            vmsFullYfmMessage.setDqdsyfphm("");
        } else {
            // 优化查询方式，减少数据库压力
            Page<VmsFullYfmDetails> page = new Page<>(1, 1);
            Page<VmsFullYfmDetails> IPage = vmsFullYfmDetailsService.page(page, queryWrapper);
            vmsFullYfmMessage.setHdsyzs((long) count);
            vmsFullYfmMessage.setDqdsyfphm(IPage.getRecords().get(0).getFphm());
        }
        vmsFullYfmMessage.setUpdateUser(tokenUser.getUserCode());
        vmsFullYfmMessage.setUpdateUsername(tokenUser.getUserName());
        vmsFullYfmMessage.setUpdateTime(new Date());
        this.updateById(vmsFullYfmMessage);

        return Result.OK();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<VmsFullYfmDetails> yfmDistribution(List<VmsFullYfmMessage> yfmMessageList, Long size, TokenUser tokenUser) {
        if (yfmMessageList == null) {
            yfmMessageList = getYfmByDeptCode(tokenUser.getDeptCode());
        }

        // 分配预赋码
        List<VmsFullYfmDetails> yfmDetailsList = new ArrayList<>();
        for (VmsFullYfmMessage yfmMessage : yfmMessageList) {
            LambdaQueryWrapper<VmsFullYfmDetails> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(VmsFullYfmDetails::getYfmid, yfmMessage.getYfmid());
            queryWrapper.eq(VmsFullYfmDetails::getUseStatus, CommonConstant.STR_0);
            queryWrapper.eq(VmsFullYfmDetails::getDelFlag, CommonConstant.STR_0);
            queryWrapper.orderByAsc(VmsFullYfmDetails::getFphm);

            if (yfmMessage.getHdsyzs() >= size) {
                Page<VmsFullYfmDetails> page = new Page<>(1, size);
                Page<VmsFullYfmDetails> yfmDetailsPage = vmsFullYfmDetailsService.page(page, queryWrapper);
                List<VmsFullYfmDetails> list = yfmDetailsPage.getRecords();
                yfmDetailsList.addAll(list);

                // 修改预赋码使用状态为已使用
                list = list.stream().peek(yfmDetails -> {
                    yfmDetails.setUseStatus(CommonConstant.STR_1);
                    yfmDetails.setUpdateUser(tokenUser.getUserCode());
                    yfmDetails.setUpdateTime(new Date());
                }).collect(Collectors.toList());
                vmsFullYfmDetailsService.updateBatchById(list);

                // 更新号段剩余总数、当前待使用发票号码
                updateYfmByDetail(yfmMessage, tokenUser);

                break;
            } else {
                List<VmsFullYfmDetails> list = vmsFullYfmDetailsService.list(queryWrapper);
                yfmDetailsList.addAll(list);

                // 修改预赋码使用状态为已使用
                list = list.stream().peek(yfmDetails -> {
                    yfmDetails.setUseStatus(CommonConstant.STR_1);
                    yfmDetails.setUpdateUser(tokenUser.getUserCode());
                    yfmDetails.setUpdateTime(new Date());
                }).collect(Collectors.toList());
                vmsFullYfmDetailsService.updateBatchById(list);

                // 更新号段剩余总数、当前待使用发票号码
                updateYfmByDetail(yfmMessage, tokenUser);

                // 修改数量，继续循环
                size = size - list.size();
            }
        }

        return yfmDetailsList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Object> rollBackYfm(String fphm, TokenUser tokenUser) {
        // 根据发票号码获取预赋码详情信息
        LambdaQueryWrapper<VmsFullYfmDetails> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(VmsFullYfmDetails::getFphm, fphm);
        VmsFullYfmDetails yfmDetail = vmsFullYfmDetailsService.getOne(queryWrapper);

        // 将预赋码详情修改为未使用
        yfmDetail.setUseStatus(CommonConstant.STR_0);
        yfmDetail.setFplx("");
        yfmDetail.setFoidid("");
        yfmDetail.setKplx("");
        yfmDetail.setUpdateUser(tokenUser.getUserCode());
        yfmDetail.setUpdateTime(new Date());
        vmsFullYfmDetailsService.updateYfmById(yfmDetail);

        LambdaQueryWrapper<VmsFullYfmMessage> yfmQueryWrapper = new LambdaQueryWrapper<>();
        yfmQueryWrapper.eq(VmsFullYfmMessage::getYfmid, yfmDetail.getYfmid());
        VmsFullYfmMessage yfmMessage = this.getOne(yfmQueryWrapper);

        // 更新号段剩余总数、当前待使用发票号码
        return updateYfmByDetail(yfmMessage, tokenUser);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Object> invalidYearYfm(String deptCode, TokenUser userInfo) {
        List<VmsFullYfmMessage> yfmMessageList = getYfmByDeptCode(deptCode);
        if (CollectionUtil.isNotEmpty(yfmMessageList)) {
            for (VmsFullYfmMessage yfmMessage : yfmMessageList) {
                // 根据预赋码id获取预赋码明细信息
                LambdaQueryWrapper<VmsFullYfmDetails> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(VmsFullYfmDetails::getYfmid, yfmMessage.getYfmid());
                queryWrapper.eq(VmsFullYfmDetails::getUseStatus, CommonConstant.STR_0);
                queryWrapper.orderByAsc(VmsFullYfmDetails::getDetailId);
                List<VmsFullYfmDetails> yfmDetailList = vmsFullYfmDetailsService.list(queryWrapper);
                if (CollectionUtil.isNotEmpty(yfmDetailList)) {
                    for (VmsFullYfmDetails yfmDetail : yfmDetailList) {
                        // 将预赋码明细的删除状态修改为已删除
                        LambdaUpdateWrapper<VmsFullYfmDetails> update = new LambdaUpdateWrapper<>();
                        update.set(VmsFullYfmDetails::getDelFlag, CommonConstant.STR_1);
                        update.set(VmsFullYfmDetails::getUpdateUser, userInfo.getUserCode());
                        update.set(VmsFullYfmDetails::getUpdateTime, new Date());
                        update.eq(VmsFullYfmDetails::getDetailId, yfmDetail.getDetailId());
                        vmsFullYfmDetailsService.update(update);
                    }
                    // 更新号段剩余总数、当前待使用发票号码
                    updateYfmByDetail(yfmMessage, userInfo);
                }
            }
        }
        return Result.OK();
    }

}
